package controllers

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/bytesfield/golang-gin-auth-service/src/app/responses"
	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
)

// HolderDetail 表示单个地址持有者数据
type HolderDetail struct {
	Address                string `json:"address"`
	OverallBalance         string `json:"overallBalance"`
	TransferableBalance    string `json:"transferableBalance"`
	AvailableBalance       string `json:"availableBalance"`
	AvailableBalanceSafe   string `json:"availableBalanceSafe"`
	AvailableBalanceUnSafe string `json:"availableBalanceUnSafe"`
	Satoshi                int    `json:"satoshi"`
}

// APIResponse 表示接口返回的响应结构
type APIResponse struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Data struct {
		Height int            `json:"height"`
		Total  int            `json:"total"`
		Start  int            `json:"start"`
		Detail []HolderDetail `json:"detail"`
	} `json:"data"`
}

// AddressBalanceResponse 是获取地址余额的响应结构体
type AddressBalanceResponse struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Data struct {
		Address                   string `json:"address"`
		Satoshi                   int    `json:"satoshi"`
		PendingSatoshi            int    `json:"pendingSatoshi"`
		UtxoCount                 int    `json:"utxoCount"`
		BtcSatoshi                int    `json:"btcSatoshi"`
		BtcPendingSatoshi         int    `json:"btcPendingSatoshi"`
		BtcUtxoCount              int    `json:"btcUtxoCount"`
		InscriptionSatoshi        int    `json:"inscriptionSatoshi"`
		InscriptionPendingSatoshi int    `json:"inscriptionPendingSatoshi"`
		InscriptionUtxoCount      int    `json:"inscriptionUtxoCount"`
	} `json:"data"`
}

type Resp struct {
	Text string `json:"text"`
}

// DownloadDataAsExcel 将接口数据转换为 Excel 格式并返回
func (server *Server) DownloadDataAsExcel(ctx *gin.Context) {
	b, err := ioutil.ReadAll(ctx.Request.Body)
	if err != nil {
		log.Printf("Error reading request body: %v", err)
		responses.ValidationError(ctx, "Validation Error", err)
		return
	}

	resp := Resp{}
	err = json.Unmarshal(b, &resp)
	if err != nil || resp.Text == "" {
		log.Printf("Invalid JSON or empty text in request body: %v", err)
		responses.ValidationError(ctx, "Invalid input", err)
		return
	}

	lines := strings.Split(resp.Text, "\n")
	if len(lines) <= 0 {
		log.Println("No data found in input text")
		return
	}

	const (
		baseURL = "https://open-api-fractal.unisat.io/v1/indexer/brc20/HPMETA/holders"
		limit   = 500 // 每页数据量
		delay   = 1   // 请求间隔时间，单位秒
	)

	start := 0
	var apiResponse APIResponse
	excelData := map[string]HolderDetail{}

	// 分页加载数据
	for {
		url := fmt.Sprintf("%s?start=%d&limit=%d", baseURL, start, limit)
		log.Printf("Fetching data from URL: %s\n", url)

		body, err := fetchPageData(url)
		if err != nil {
			log.Printf("Error fetching data from URL %s: %v", url, err)
			ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}

		if err := json.Unmarshal(body, &apiResponse); err != nil {
			log.Printf("Error unmarshalling API response: %v", err)
			continue
		}

		// 检查是否还有数据
		if len(apiResponse.Data.Detail) == 0 {
			log.Println("No more data available")
			break
		}

		// 获取每个地址的余额数据
		for _, v := range apiResponse.Data.Detail {
			excelData[v.Address] = HolderDetail{
				Address:                v.Address,
				OverallBalance:         v.OverallBalance,
				TransferableBalance:    v.TransferableBalance,
				AvailableBalance:       v.AvailableBalance,
				AvailableBalanceSafe:   v.AvailableBalanceSafe,
				AvailableBalanceUnSafe: v.AvailableBalanceUnSafe,
			}
		}
		start += limit
	}
	newExcelData := []HolderDetail{}
	for _, v := range lines {
		balanceInfo, err := GetAddressBalance(v)
		satoshi := 0
		if err != nil {
			GetAddressBalance(v)
			time.Sleep(1)
		}
		if err == nil && balanceInfo != nil {
			satoshi = balanceInfo.Data.Satoshi
		}
		newExcelData = append(newExcelData, HolderDetail{
			Address:                v,
			OverallBalance:         excelData[v].OverallBalance,
			TransferableBalance:    excelData[v].TransferableBalance,
			AvailableBalance:       excelData[v].AvailableBalance,
			AvailableBalanceSafe:   excelData[v].AvailableBalanceSafe,
			AvailableBalanceUnSafe: excelData[v].AvailableBalanceUnSafe,
			Satoshi:                satoshi,
		})
	}
	// 生成 Excel 文件
	file := excelize.NewFile()
	sheetName := "Holders"
	index, _ := file.NewSheet(sheetName)

	// 设置表头
	file.SetCellValue(sheetName, "A1", "Address")
	file.SetCellValue(sheetName, "G1", "Satoshi")
	file.SetCellValue(sheetName, "B1", "OverallBalance")
	file.SetCellValue(sheetName, "C1", "TransferableBalance")
	file.SetCellValue(sheetName, "D1", "AvailableBalance")
	file.SetCellValue(sheetName, "E1", "AvailableBalanceSafe")
	file.SetCellValue(sheetName, "F1", "AvailableBalanceUnSafe")

	overallBalanceTotal := 0.0
	transferableBalanceTotal := 0.0
	availableBalanceTotal := 0.0
	availableBalanceSafeTotal := 0.0
	availableBalanceUnSafeTotal := 0.0
	satoshiTotal := 0.0

	row := 0
	// 填充数据
	for i, data := range newExcelData {
		row = i + 2
		// 强制转换为 float64
		overallBalance, _ := strconv.ParseFloat(fmt.Sprintf("%v", data.OverallBalance), 64)
		transferableBalance, _ := strconv.ParseFloat(fmt.Sprintf("%v", data.TransferableBalance), 64)
		availableBalance, _ := strconv.ParseFloat(fmt.Sprintf("%v", data.AvailableBalance), 64)
		availableBalanceSafe, _ := strconv.ParseFloat(fmt.Sprintf("%v", data.AvailableBalanceSafe), 64)
		availableBalanceUnSafe, _ := strconv.ParseFloat(fmt.Sprintf("%v", data.AvailableBalanceUnSafe), 64)
		satoshi, _ := strconv.ParseFloat(fmt.Sprintf("%v", data.Satoshi), 64)

		overallBalance = overallBalance / 100000000
		transferableBalance = transferableBalance / 100000000
		availableBalance = availableBalance / 100000000
		availableBalanceSafe = availableBalanceSafe / 100000000
		availableBalanceUnSafe = availableBalanceUnSafe / 100000000
		satoshi = satoshi / 100000000

		overallBalanceTotal += overallBalance
		transferableBalanceTotal += transferableBalance
		availableBalanceTotal += availableBalance
		availableBalanceSafeTotal += availableBalanceSafe
		availableBalanceUnSafeTotal += availableBalanceUnSafe
		satoshiTotal += satoshi
		// 写入 Excel
		file.SetCellValue(sheetName, fmt.Sprintf("A%d", row), data.Address)
		file.SetCellValue(sheetName, fmt.Sprintf("B%d", row), overallBalance)
		file.SetCellValue(sheetName, fmt.Sprintf("C%d", row), transferableBalance)
		file.SetCellValue(sheetName, fmt.Sprintf("D%d", row), availableBalance)
		file.SetCellValue(sheetName, fmt.Sprintf("E%d", row), availableBalanceSafe)
		file.SetCellValue(sheetName, fmt.Sprintf("F%d", row), availableBalanceUnSafe)
		file.SetCellValue(sheetName, fmt.Sprintf("G%d", row), satoshi)
	}
	file.SetCellValue(sheetName, fmt.Sprintf("A%d", row+1), "总计")
	file.SetCellValue(sheetName, fmt.Sprintf("B%d", row+1), overallBalanceTotal)
	file.SetCellValue(sheetName, fmt.Sprintf("C%d", row+1), transferableBalanceTotal)
	file.SetCellValue(sheetName, fmt.Sprintf("D%d", row+1), availableBalanceTotal)
	file.SetCellValue(sheetName, fmt.Sprintf("E%d", row+1), availableBalanceSafeTotal)
	file.SetCellValue(sheetName, fmt.Sprintf("F%d", row+1), availableBalanceUnSafeTotal)
	file.SetCellValue(sheetName, fmt.Sprintf("G%d", row+1), satoshiTotal)

	// 设置工作表为当前活动工作表
	file.SetActiveSheet(index)

	// 返回 Excel 文件
	fileName := "holders_data.csv"
	ctx.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
	ctx.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", fileName))
	if err := file.Write(ctx.Writer); err != nil {
		log.Printf("Failed to write excel file: %v", err)
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate Excel file"})
		return
	}
}

// GetAddressBalance 获取地址余额和铭文数据
func GetAddressBalance(address string) (*AddressBalanceResponse, error) {
	url := fmt.Sprintf("https://open-api-fractal.unisat.io/v1/indexer/address/%s/balance", address)

	body, err := fetchPageData(url)
	if err != nil {
		return nil, fmt.Errorf("获取地址数据失败: %v", err)
	}

	var response AddressBalanceResponse
	if err := json.Unmarshal(body, &response); err != nil {
		return nil, fmt.Errorf("解析数据失败: %v", err)
	}

	return &response, nil
}

// fetchPageData 发送 HTTP 请求并返回响应内容
func fetchPageData(url string) ([]byte, error) {
	client := &http.Client{}
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return nil, fmt.Errorf("请求失败: %v", err)
	}

	req.Header = map[string][]string{
		"Accept":        {"*/*"},
		"Authorization": {"Bearer c9fb2b23fb1b7a01cd00f17d055bba244879606432d3215ea3465e6fa8d04ed2"},
		"Origin":        {"https://docs.unisat.io"},
		"Referer":       {"https://docs.unisat.io/dev/unisat-developer-center/fractal-bitcoin/brc-20/get-brc-20-holders"},
		"User-Agent":    {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"},
	}

	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("请求执行失败: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("响应状态码异常: %d", resp.StatusCode)
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应内容失败: %v", err)
	}

	return body, nil
}
func contains(slice []string, target string) bool {
	for _, str := range slice {
		if str == target {
			return true
		}
	}
	return false
}
